/**
 * 
 */
package com.boshanam.model.vos.domain.user;

import java.util.Date;

import org.springframework.security.GrantedAuthority;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UserDetailsService;

/**
 * 
 * 
 * Models core user information retieved by an {@link UserDetailsService}.
 * <p>
 * Implemented with value object semantics (immutable after construction, like a
 * <code>String</code>). Developers may use this class directly, or subclass it.
 * </p>
 * 
 * This VO is intended to be used in AcegiSecurity Context, so it is immutable
 * with the intention that credentials with in Security context should not be
 * modified. It is the Default UserVO returned by DAO's. To facilitate users to
 * change (update) his credentials, values will be copied to new UserVO through
 * constructor then send to UI (Views), where user modifies them through forms
 * and updated by Model. When ever modifications required new instance will be
 * created with the updated new valued and persisted.
 * 
 * 
 * NOTE: When sorted, the sort order is as the following
 * firstName, MiddleName, lastName, UserID, Email.
 * Assumed atleast Email must always be present.
 * 
 * @author Sivakumar Y, UserAttributes.java Dec 21, 2009 12:45:25 PM
 *         www.ibigbang.net shiva.forums@gmail.com
 */
public class UserVOImmutable implements UserDetails, Comparable<UserVOImmutable> {

	private static final long serialVersionUID = 1L;

	protected String ID;

	protected String username;
	protected String password;

	protected String firstName;
	protected String lastName;
	protected String middleName;
	protected String phoneNumber;
	protected Date birthDate;

	protected String email;

	protected UserSettingsVO userSettings;
	protected GrantedAuthority[] authorities;
	protected boolean accountNonExpired;
	protected boolean accountNonLocked;
	protected boolean credentialsNonExpired;
	protected boolean enabled;
	protected boolean verified;
	
	protected String signinHistory;
	
	protected String description;

	protected UserVOImmutable() {
	}

	/**
	 * 
	 * @param id
	 * @param firstName
	 * @param lastName
	 * @param middleName
	 * @param phoneNumber
	 * @param username
	 * @param password
	 * @param email
	 * @param userSettings
	 * @param enabled
	 * @param accountNonExpired
	 * @param credentialsNonExpired
	 * @param accountNonLocked
	 * @param authorities
	 * @param description
	 */
	public UserVOImmutable(String id, String firstName, String lastName,
			String middleName, String phoneNumber, Date birthDate, String username,
			String password, String email, UserSettingsVO userSettings,
			boolean enabled, boolean verified, boolean accountNonExpired,
			boolean credentialsNonExpired, boolean accountNonLocked,
			GrantedAuthority[] authorities, String signinHistory, String description) {
		super();
		ID = id;
		this.firstName = firstName;
		this.lastName = lastName;
		this.middleName = middleName;
		this.phoneNumber = phoneNumber;
		this.birthDate = birthDate;
		this.username = username;
		this.password = password;
		this.accountNonExpired = accountNonExpired;
		this.accountNonLocked = accountNonLocked;
		this.authorities = authorities;
		this.credentialsNonExpired = credentialsNonExpired;
		this.email = email;
		this.enabled = enabled;
		this.verified = verified;
		this.userSettings = userSettings;
		this.signinHistory = signinHistory;
		this.description = description;
	}

	public String getID() {
		return ID;
	}

	public String getUsername() {
		return username;
	}

	public String getFirstName() {
		return firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public String getMiddleName() {
		return middleName;
	}

	public String getPhoneNumber() {
		return phoneNumber;
	}

	public Date getBirthDate() {
		return birthDate;
	}

	public void setBirthDate(Date birthDate) {
		this.birthDate = birthDate;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public void setMiddleName(String middleName) {
		this.middleName = middleName;
	}

	public void setPhoneNumber(String phoneNumber) {
		this.phoneNumber = phoneNumber;
	}

	public String getPassword() {
		return password;
	}

	public String getEmail() {
		return email;
	}

	public UserSettingsVO getUserSettings() {
		return userSettings;
	}

	public GrantedAuthority[] getAuthorities() {
		return authorities;
	}

	public boolean isAccountNonExpired() {
		return accountNonExpired;
	}

	public boolean isAccountNonLocked() {
		return accountNonLocked;
	}

	public boolean isVerified() {
		return verified;
	}

	public void setVerified(boolean verified) {
		this.verified = verified;
	}

	public boolean isCredentialsNonExpired() {
		return credentialsNonExpired;
	}

	public boolean isEnabled() {
		return enabled;
	}

	protected void setID(String id) {
		ID = id;
	}

	protected void setUsername(String username) {
		this.username = username;
	}

	protected void setPassword(String password) {
		this.password = password;
	}

	protected void setEmail(String email) {
		this.email = email;
	}

	protected void setUserSettings(UserSettingsVO userSettings) {
		this.userSettings = userSettings;
	}

	protected void setAuthorities(GrantedAuthority[] authorities) {
		this.authorities = authorities;
	}

	protected void setAccountNonExpired(boolean accountNonExpired) {
		this.accountNonExpired = accountNonExpired;
	}

	protected void setAccountNonLocked(boolean accountNonLocked) {
		this.accountNonLocked = accountNonLocked;
	}

	protected void setCredentialsNonExpired(boolean credentialsNonExpired) {
		this.credentialsNonExpired = credentialsNonExpired;
	}

	protected void setEnabled(boolean enabled) {
		this.enabled = enabled;
	}

	public int hashCode() {
		int code = 9792;

		if (this.getAuthorities() != null) {
			for (int i = 0; i < this.getAuthorities().length; i++) {
				code = code * (this.getAuthorities()[i].hashCode() % 7);
			}
		}

		if (this.getPassword() != null) {
			code = code * (this.getPassword().hashCode() % 7);
		}

		if (this.getUsername() != null) {
			code = code * (this.getUsername().hashCode() % 7);
		}

		if (this.isAccountNonExpired()) {
			code = code * -2;
		}

		if (this.isAccountNonLocked()) {
			code = code * -3;
		}

		if (this.isCredentialsNonExpired()) {
			code = code * -5;
		}

		if (this.isEnabled()) {
			code = code * -7;
		}

		return code;
	}

	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append(super.toString()).append(": ");
		sb.append("Username: ").append(this.username).append("; ");
		sb.append("Email: ").append(this.email).append("; ");
		sb.append("First Name: ").append(this.firstName).append("; ");
		sb.append("Middle Name: ").append(this.middleName).append("; ");
		sb.append("Last Name: ").append(this.lastName).append("; ");
		sb.append("Password: [PROTECTED]; ");
		sb.append("Enabled: ").append(this.enabled).append("; ");
		sb.append("AccountNonExpired: ").append(this.accountNonExpired).append(
				"; ");
		sb.append("credentialsNonExpired: ").append(this.credentialsNonExpired)
				.append("; ");
		sb.append("AccountNonLocked: ").append(this.accountNonLocked).append(
				"; ");

		if (this.getAuthorities() != null) {
			sb.append("Granted Authorities: ");

			for (int i = 0; i < this.getAuthorities().length; i++) {
				if (i > 0) {
					sb.append(", ");
				}

				sb.append(this.getAuthorities()[i].toString());
			}
		} else {
			sb.append("Not granted any authorities");
		}

		return sb.toString();
	}

	protected void setDescription(String description) {
		this.description = description;
	}

	public String getSigninHistory() {
		return signinHistory;
	}

	public void setSigninHistory(String signinHistory) {
		this.signinHistory = signinHistory;
	}

	public String getDescription() {
		return description;
	}

	/**
	 * NOTE: When sorted, the sort order is as the following
	 *  firstName, MiddleName, lastName, UserID, Email.
	 *  Assumed atleast Email must always be present.
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
	 */
	@Override
	public int compareTo(UserVOImmutable o) {
		if(getFirstName() != null && o.getFirstName() != null && getFirstName().compareToIgnoreCase(o.getFirstName()) != 0){
			return getFirstName().compareToIgnoreCase(o.getFirstName());
		}
		if(getMiddleName() != null && o.getMiddleName() != null && getMiddleName().compareToIgnoreCase(o.getMiddleName()) != 0){
			return getMiddleName().compareToIgnoreCase(o.getMiddleName());
		}
		if(getLastName() != null && o.getLastName() != null && getLastName().compareToIgnoreCase(o.getLastName()) != 0){
			return getLastName().compareToIgnoreCase(o.getLastName());
		}
		if(getUsername() != null && o.getUsername() != null && getUsername().compareToIgnoreCase(o.getUsername()) != 0){
			return getUsername().compareToIgnoreCase(o.getUsername());
		}
		if(getEmail() != null && o.getEmail() != null && getEmail().compareToIgnoreCase(o.getEmail()) != 0){
			return getEmail().compareToIgnoreCase(o.getEmail());
		}
		return 0;
	}

}
